package org.anachronos.jeep.core.trace;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.anachronos.jeep.core.trace.impl.Class;
import org.anachronos.jeep.core.trace.impl.Method;
import org.anachronos.jeep.core.trace.impl.Package;
import org.ow2.util.asm.Type;

public class MethodDescriptionConverter {
	private static Pattern METHOD_DESC_PATTERN =
		Pattern.compile("(.*)\\.(\\w.*)(\\(.*\\).*)");
	private static Pattern CLASS_NAME_PATTERN =
		Pattern.compile("(.*)/([^/]*)");
	private MethodDescriptionConverter() {
		// this is a static helper!
	}
	
	public static String convert(final String methodDesc) {
		final StringBuffer buffer = new StringBuffer("(");
		final Type[] argumentTypes = Type.getArgumentTypes(methodDesc);
		for (int i = 0; i < argumentTypes.length; i++) {
			if (i > 0) {
				buffer.append(",");
			}
			buffer.append(argumentTypes[i].getClassName());
		}
		buffer.append(")").append(Type.getReturnType(methodDesc).getClassName());
		return buffer.toString();
	}
	
	public static Method createAndAddToRoot(final Package root, final String fullMethodDesc) {
		final Matcher methodDescMatcher = METHOD_DESC_PATTERN.matcher(fullMethodDesc);
		if (!methodDescMatcher.matches()) {
			throw new IllegalArgumentException("Method description " + fullMethodDesc + " is invalid!");
		}
		final String methodName = methodDescMatcher.group(2);
		final String desc = methodDescMatcher.group(3).replaceAll("/", ".");
		final org.ow2.util.asm.commons.Method asmMethod = new 
			org.ow2.util.asm.commons.Method(methodName, desc);
		final List<Class> argumentTypes = convert(root, asmMethod.getArgumentTypes());
		final Class returnType = convert(root, asmMethod.getReturnType()).get(0);
		final Method method = new Method(asmMethod.getName(), fullMethodDesc, argumentTypes, returnType);
		final String packageClassName = methodDescMatcher.group(1);
		final Matcher classNameMatcher = CLASS_NAME_PATTERN.matcher(packageClassName);
		if (!classNameMatcher.matches()) {
			throw new IllegalArgumentException("Class name " + packageClassName + " is invalid!");
		}
		final String pkg = classNameMatcher.group(1);
		final Package parent = root.lookupOrCreate(Package.class, pkg.split("/"));
		final String className = classNameMatcher.group(2);
		final Class clazz = parent.lookupOrCreate(Class.class, className);
		clazz.add(method);
		return method;
	}

	private static List<Class> convert(final Package root, final Type... types) {
		final List<Class> result = new ArrayList<Class>();
		for (Type type : types) {
			final String className = type.getClassName();
			final String[] names = className.split("\\.");
			final String[] packages = Arrays.copyOf(names, names.length - 1);
			root.lookupOrCreate(Package.class, packages);
			final Class clazzType = root.lookupOrCreate(Class.class, names);
			result.add(clazzType);
		}
		return result;
	}
}
